#! /usr/bin/env bash
# @author: Philippe Coval <rzr@gna.org>

set -x
set -e

prefix="file://${HOME}/var/cache/url/git-mirror/"
PATH=$PATH:"${HOME}/bin"
VARDIR="${HOME}/var/lib/git.sh.dir"
gitdir="${HOME}/var/cache/url/git-mirror/"
archivedir="${HOME}/var/cache/url/git-archive/"


log_()
{
    echo "$@"
}


op_help_()
{
    cat<<EOF
EXTRA commands :

git file $file # shows history
EOF
    git help
}


# rename clone arg0
op_cache_()
{
    echo "#{ op cache : $@"
    local dir="${HOME}/var/lib/git.sh.dir/"
    local file="${dir}/list/git.urls"

    [ ! -r "$1" ] || file="$1"

    local failed_file="${file}._ko.urls"
    local success_file="${file}._ok.urls"

    cat "$file" | uniq | while read url ; do
        { $0 clone --mirror "$url" \
            && echo "$url" | tee -a "${success_file}" ; } \
            || echo "$url" | tee -a "${failed_file}"
    done
    sort "${file}" | uniq > "${file}.tmp" && mv "${file}.tmp" "${file}"
}


git_fetch_()
{
    date
    time git fetch -v --progress "$@"
    git fetch -v --prune --tags "$@"
}


git_pull_()
{
    time git pull -v --progress "$@"
}


clone_mirror_()
{
    set -x
    #log_ "#{ op_clone_ : $@"
    url="$1" && shift
    local pwd="${pwd}"
    package=$(basename "${url/://}")
    dirname=$(dirname "${url/:///}")

    mkdir -p "${gitdir}/${dirname}" "${archivedir}/${url}//"

    cd "${gitdir}/${dirname}" || return 1

    pwd && pwd="$(pwd)"

    cd "${pwd}/$package" || \
        { pwd && time git clone --mirror "${url}" "$package" \
        && echo time tar cfz "${archivedir}/${url}/${project}/${package}.tar.gz" "${package}" ; }

    cd "${pwd}/$package" || return 2

    time git_fetch_ --tags || time git_fetch_ --tags --force || log_ "todo"
    time git_fetch_ --all || time git_fetch_ --all --force || log_ "error: $url"
    cd "${pwd}"
    #log_ "#} op_clone_"
}


clone_local_()
{
    local pwd=$(pwd)
    cd "${pwd}/${basename}" || time git clone "$prefix/${url_path}" || return 0
    cd "${pwd}/${basename}" || return 0
    pwd
    git remote set-url origin "$url"
    git_fetch_ --all || echo "warning: "
    git pull --all  || echo "warning: "
    pwd
}


op_init_()
{
    git init
    touch .gitignore

    git add .gitignore
    git commit -sam 'init:'
    git branch init
    cat<<EOF>> .gitignore
*~
*.tmp
EOF
    git commit -sam 'ignore: backup files'

}


op_info_()
{
    ref="HEAD"
    ref="$1"
    git show-ref | grep "$ref"
}


op_clone_()
{
    pwd="$(pwd)"
    file="${HOME}/var/lib/git.sh.dir/list/git.urls"
    dir=$(dirname -- "${file/:/}")
    mkdir -p "${dir}"
    url="https://github.com/rzr/gnome-control-center.git"

    opt_mirror=0

    case $1 in
        --mirror)
            opt_mirror=1
            shift
            ;;
        *)
            ;;
    esac


    [ "_" = "_$1" ] || url="$1"

    #   url=$(echo "$url" | sed -e 's|:[^/]|:/|g')
    #   url=$(echo "$url" | sed -e 's|//|/|g')
    url_path="${url/://}"
    basename=$(basename "${url_path/.git/}")
    d="$HOME/var/cache/url/git/${url_path}/src"

    echo "# url_path=${url_path}"

    echo "$@" | tee -a "$file"

    clone_mirror_ "${url}"

    [ "1" != "${opt_mirror}" ] || return 0

    cd "${pwd}"

    [ "_${HOME}" != "_$(pwd)" ] || {
        mkdir -p "$d" || return 1
        cd "$d" ;
    }

    clone_local_
}


op_remote_()
{
    c="$1" && shift

    case $c in

        add)
            name="$1" && shift
            url="$1" && shift
            local_url="${url/://}"
            pwd="$(pwd)"
            cd ${HOME} && git.sh clone --mirror "$url"  || echo "# cached"
            cd "${pwd}"
            git remote add "$name" "$prefix/${local_url}"
            git fetch "${name}"
            git remote set-url "$name" "${url}"
            git fetch "${name}" # overide fetch not set-url # TODO
            ;;
        *)
            git remote $c $@
            ;;
    esac
}


op_setup_()
{
    cat<<EOF | tee ~/.bashrc
alias g=~/bin/git.sh
alias git=~/bin/git.sh

EOF
}


op_file_()
{
    file="$1"
    gitk HEAD -- bin/git.sh

    git log "$file" | grep '^commit ' | cut -d' ' -f2 | while read id ; do
        echo "#{ $id ###" &&
        git show "$id:$file"
        #gitk $id -- $file
    done

    echo "quit now will commit contents (all files) quit now or press return"
    read t

    git log "$file" | grep '^commit ' | cut -d' ' -f2 | while read id ; do
        echo "#{ $id ###" && git show "$id" ;
    done
}


op_resolve()
{
    set +e
    git status | grep "deleted:" | cut -d: -f 2 | while read t ; do git rm "$t" ; done
    git status | grep "deleted by us:" | cut -d: -f 2 | while read t ; do git rm "$t" ; done
    git status \
        | grep "new file:" | cut -d: -f 2 | while read t ; do git add "$t" ; done
}


op_rm_diff()
{
    git status \
        | grep "modified:" | cut -d: -f 2 | while read t ; do rm "$t" ; done
}


op_fu_()
{
    git status
    git difftool .
    echo "#? commit?"
    read t
    git commit -sam 'fixup' || echo "ignored:"
    git rebase -i HEAD~2
    gitk
}


op_rtagrm_()
{
    exit
    git tag -d "$1"
    git push --delete "$origin" "$tag"

}


op_skip_()
{
    set +e
    # TODO:
    while git status ; do
        git rebase --skip  ;
        git status | grep 'nothing to commit, working directory clean' \
            && return 1
    done
}


op_branches()
{
    upstream="master"
    upstream=$(git branch | sed -e 's|* ||g')
    git branch -a \
        | grep origin | cut -d '/' -f 3 | grep -v -- '->' | grep -v 'remotes' \
        | while read branch ; do \
        git checkout "$branch" \
        || git checkout -b "$branch" "remotes/origin/$branch" ; \
        done \
        &&  git checkout "$upstream"
}


op_export()
{
    upstream="upstream"
    pwd="$(pwd)"
    mkdir -p "${VARDIR}/rootfs/$pwd"
    git format-patch -o "${VARDIR}/rootfs/${pwd}" "${upstream}"
}


op_describe_()
{
    package=$(ls packaging/*.spec | sed -e 's|.*/\(.*\).spec|\1|g')
    package=$(basename "`dirname $(pwd)`")
    hash=HEAD
    to_version=$(git describe "$hash" \
        | tail -n 1 | sed -e "s|${package}-||g" \
        | sed -e 's|^[vV]\([0-9]*.*\)|\1|g' \
        | tr -- '-' '+' \
        | sed -e 's|[vV]?\([0-9]*.*\)|\1|g' \
        | sed -e 's|^[^0-9]*||g' -e 's|_|.|g' )

    echo "to_version=$to_version" # update to X.Y.Z+... form
}


op_wip_()
{
    git status
    git commit -sam "WIP: $@"
}


op_sync_()
{
    git config --get remote.origin.url
    op_wip_
    git pull
    git status
    git push
}


op_tree_()
{
    git log --graph --simplify-by-decoration --pretty=format:'%d' --all
}


op_rebase_our_()
{
    tag="$1"
    git rebase "$tag" -Xours
}


op_resolved_()
{
    git add .
    git status | grep 'deleted by us:' | cut -d: -f 2 | xargs git rm \
        || echo "ignore"
    git status | grep 'deleted by ' | cut -d: -f 2 | xargs git rm \
        || echo "ignore"
    git status
}


op_continue_()
{
    tmp=$(mktemp)".tmp"

    while [ 1 = 1 ] ; do
        git status | tee  "$tmp-pre.tmp"
        git status | grep 'rebase in progress'  || return 1
        op_resolved_
        git rebase --continue ; sleep 5
        git status | tee "$tmp-post.tmp"
        [ ! diff "$tmp-pre.tmp" "$tmp-post.tmp" ] || return 0
        #       return 2
    done
}

op_keep_()
{
    revision="$1"
    git status \
        | grep 'both modified:' | cut -d: -f 2 | while read t ; do \
        git checkout "$revision" -- "$t" ;
    done
}


op_cgit_()
{
    url="http://git.enlightenment.org/"
    [ "" = "$1" ] || url="$1"
    file="${VARDIR}/list/uri/${url/://}/cgit.urls"
    dir=$(dirname -- "${file}") && mkdir -p "${dir}"

    lynx -dump "$url" \
        | grep -e " *[0-9]*. $url.*.git" \
        | sed -e 's| *[0-9]*. \(.*.git\)|\1|g' \
        | sort | uniq \
        > "$file"

    op_cache_ "$file"
}


op_gerrit_()
{
    h="review.tizen.org"
    url="gerrit://$h"
    [ "" = "$1" ] || url="$1"
    file="${VARDIR}/list/uri/${url/://}/ls-projects.txt"
    dir=$(dirname -- "$file") && mkdir -p "${dir}"

    ssh "$h" gerrit ls-projects \
        | tee "${file}"

    sort ${file} | while read project ; do
        echo "$h:/$project" ;
    done > "${dir}/index.urls"
}


op_ls_()
{
    git log --pretty=format:"%h %s" --graph
}


op_ls_mine_()
{
    git log --author=$EMAIL
}

op_contain_()
{
    hash=HEAD
    git branch --contains $hash
}


main_()
{
    echo "#{ main : $@"
    op="$1" && shift
    pwd

    case $op in

        op)
            op="$1"
            shift
            "op_${op}_" "$@"
            ;;

        sync)
            # TODO : git branch -a | while read branch ; do git
            ;;

        commit)
            echo '012345678901234567890123456789012345678901234567890123456789ABCDEF'
            git commit "$@"
            git log -1 HEAD | cut -b 1-65
            echo '012345678901234567890123456789012345678901234567890123456789ABCDEF'
            ;;

        clone | file | setup | remote)
            "op_${op}_" "$@"
            ;;

        fetch | pull)
            sleep 1
            time git "$op" -v --progress "$@"
            ;;
        op)
            op="$1" && shift
            time "op_$op" "$@"
            ;;
        *)
            sleep 1
            time git "$op" "$@"
            ;;
    esac
}


main_ "$@"

#eof
